package models

import (
	"bytes"
	"database/sql"
	"fmt"
	"strings"
)

type DalCodeGen struct {
	db *sql.DB
}
type DbColumn struct {
	Name   string
	DbType string
}

func NewCodeGen() *DalCodeGen {
	var codegen = DalCodeGen{}
	codegen.db = MysqlDb["information_schema"]
	return &codegen
}
func (this *DalCodeGen) GetDbs() []string {
	defer func() {
		if e := recover(); e != nil {
			fmt.Printf("mysqldb error %s\r\n", e)
		}
	}()
	countdata := this.db.QueryRow("SELECT COUNT(1) as N FROM `SCHEMATA`")
	var count int
	countdata.Scan(&count)
	if count <= 0 {
		return []string{}
	}
	var rsdbs = make([]string, count)
	rows, err := this.db.Query("SELECT `SCHEMA_NAME` FROM `SCHEMATA` LIMIT 1000;")
	if err != nil {
		panic(err.Error())
	}
	defer rows.Close()
	index := 0
	for rows.Next() {
		var dbName string
		rows.Scan(&dbName)
		rsdbs[index] = dbName
		index++
	}
	return rsdbs
}
func (this *DalCodeGen) GetTables(dbname string) []string {
	defer func() {
		if e := recover(); e != nil {
			fmt.Printf("mysqldb error %s\r\n", e)
		}
	}()
	countdata := this.db.QueryRow("SELECT COUNT(1) as N FROM `TABLES` WHERE TABLE_SCHEMA = ?", dbname)
	var count int
	countdata.Scan(&count)
	if count <= 0 {
		return []string{}
	}
	var rsTabs = make([]string, count)
	rows, err := this.db.Query("SELECT `TABLE_NAME` FROM `TABLES` WHERE TABLE_SCHEMA = ?", dbname)
	if err != nil {
		panic(err.Error())
	}
	defer rows.Close()
	index := 0
	for rows.Next() {
		var tbname string
		rows.Scan(&tbname)
		rsTabs[index] = tbname
		index++
	}
	return rsTabs
}

func (this *DalCodeGen) GetColumns(dbname, tabname string) []*DbColumn {
	defer func() {
		if e := recover(); e != nil {
			fmt.Printf("mysqldb error %s\r\n", e)
		}
	}()
	countdata := this.db.QueryRow("SELECT COUNT(1) as N FROM `COLUMNS` WHERE TABLE_SCHEMA = ? AND TABLE_NAME=?", dbname, tabname)
	var count int
	countdata.Scan(&count)
	if count <= 0 {
		return []*DbColumn{}
	}
	var rscols = make([]*DbColumn, count)
	rows, err := this.db.Query("SELECT `COLUMN_NAME`,`DATA_TYPE` FROM `COLUMNS` WHERE TABLE_SCHEMA = ? AND TABLE_NAME=?", dbname, tabname)
	if err != nil {
		panic(err.Error())
	}
	defer rows.Close()
	index := 0
	for rows.Next() {
		var col = DbColumn{}
		rows.Scan(&col.Name, &col.DbType)
		rscols[index] = &col
		index++
	}
	return rscols
}

// (this *Dal)CodeGen ...
func (this *DalCodeGen) CodeGen(packname, tablename string, tablefield map[string]string) string {
	var buf bytes.Buffer
	buf.WriteString("package ")
	buf.WriteString(packname)
	buf.WriteString("\n\n")
	buf.WriteString("import (\n")
	buf.WriteString("    \"database/sql\"\n")
	buf.WriteString(")\n")
	buf.WriteString("type ")
	buf.WriteString(tablename)
	buf.WriteString(" struct {\n")
	buf.WriteString("    db *sql.DB\n")
	for k, v := range tablefield {
		buf.WriteString("    ")
		buf.WriteString(k)
		buf.WriteString(" ")
		buf.WriteString(v)
		buf.WriteString("\n")
	}
	buf.WriteString("}\n\n")
	buf.WriteString(this.genCountCode(tablename))
	var sqlselectfields = make(map[string]string)
	sqlselectfields["Name"] = "Name"
	sqlselectfields["Age"] = "Age"
	buf.WriteString(this.genGetPagesCode(tablename, tablename, sqlselectfields))
	buf.WriteString(this.genDelProcSql(tablename, "ID"))
	return buf.String()
}
func (this *DalCodeGen) genCountCode(tablename string) string {
	var buf bytes.Buffer
	buf.WriteString("func (this *")
	buf.WriteString(tablename)
	buf.WriteString(") GetCount() int {\n")
	countquery := fmt.Sprintf("    countdata := this.db.QueryRow(\"SELECT COUNT(1) AS N FROM `%s`\")\n", tablename)
	buf.WriteString(countquery)
	buf.WriteString("    var count int\n")
	buf.WriteString("    countdata.Scan(&count)\n")
	buf.WriteString("    return count\n")
	buf.WriteString("}\n")
	return buf.String()
}
func (this *DalCodeGen) getGoType(dbtype string) string {
	dt := strings.ToLower(dbtype)
	if strings.Contains(dt, "int") {
		return "int"
	}
	if strings.Contains(dt, "bit") {
		return "int"
	}
	if strings.Contains(dt, "float") {
		return "float32"
	}
	if strings.Contains(dt, "double") {
		return "float64"
	}
	if strings.Contains(dt, "decimal") {
		return "float32"
	}

	return "string"
}
func (this *DalCodeGen) genGetPagesCode(typename, tablename string, fields map[string]string) string {
	var buf bytes.Buffer
	buf.WriteString("func (this *")
	buf.WriteString(tablename)
	buf.WriteString(") GetPages(page, pagesize int) []*")
	buf.WriteString(typename)
	buf.WriteString("{\n")
	buf.WriteString(fmt.Sprintf("    var rs = make([]*%s,pagesize)\n", typename))
	colstr := ""
	rowsscanstr := ""
	for k, v := range fields {
		if colstr != "" {
			colstr = colstr + ","
		}
		colstr = colstr + "`" + k + "`"
		if rowsscanstr != "" {
			rowsscanstr = rowsscanstr + ","
		}
		rowsscanstr = rowsscanstr + "&obj." + v
	}
	buf.WriteString("    startindex := (page - 1) * pagesize\n")
	buf.WriteString("    rows, err := this.db.Query(\"SELECT " + colstr + " FROM `" + tablename + "` LIMIT ?,?\",startindex, pagesize)\n")
	buf.WriteString("    if err != nil {\n        panic(err.Error())\n    }\n    defer rows.Close()\n")
	buf.WriteString("    index := 0\n")
	buf.WriteString("    for rows.Next() {\n        var obj " + typename + "{}\n")
	buf.WriteString("        rows.Scan(" + rowsscanstr + ")\n")
	buf.WriteString("        rs[index] = &obj\n")
	buf.WriteString("        index++\n    }\n")
	buf.WriteString("    return rs\n}\n")
	return buf.String()
}
func (this *DalCodeGen) genDelProcSql(tablename, pkname string) string {
	var buf bytes.Buffer
	buf.WriteString("CREATE PROCEDURE `spa_" + tablename + "_d`(IN `_" + pkname + "` INT, OUT `c` INT)\n")
	buf.WriteString("BEGIN\n")
	buf.WriteString("    delete from " + tablename + " where " + pkname + " = _" + pkname + ";\n    set c = row_count();\nEND\n")
	return buf.String()
}
func (this *DalCodeGen) genDeleteCode(tablename, pkidname string) string {
	var buf bytes.Buffer
	buf.WriteString("func (this *")
	return buf.String()
}
